/**
 * 
 */
package it.unical.canonaco.rende.igpe.game.cbv.guilayer.components;


import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.RGBImageFilter;
import java.io.File;
import java.io.IOException;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.swing.JButton;

/**
 * @author Massimo Canonaco
 */
public class OverallGUILayoutFactory 
{
	/** */
	static public final int BUTTON_STATE_ACTIVE = 0;
	
	/** */
	static public final int BUTTON_STATE_INACTIVE = 1;
	
	/** */
	static public final int BUTTON_STATE_DISABLED = 2;
	
	/** */
	static private OverallGUILayoutFactory instance;
	
	/** */
	static private ImageFilter transparentFilter;
	
	/** */
	static private int transparentColor = Color.white.getRGB() | 0xFF000000;
	/**
	 * @throws IOException  */
	static public OverallGUILayoutFactory getInstance()
	{
		if(instance == null)
		{
			instance = new OverallGUILayoutFactory();
			transparentFilter = new RGBImageFilter() {
		         
		         public final int filterRGB(int x, int y, int rgb) {
		            if ((rgb | 0xFF000000) == transparentColor) {
		               return 0x00FFFFFF & rgb;
		            } else {
		               return rgb;
		            }
		         }
		      };
		}
		
		return instance;
	}
	
//	/** */
//	private Image logo; 
	
	/** */
	private Font headerFont;
	
	/** */
	private Font paragraphFont;
	
	/** */
	private Image errorImage;
	
	/** */
	private Image selectedButton;
	
	/** */
	private Image unselectedButton;
	
	/** */
	private Color activeParagraphTextColor;
	
	/** */
	private Color activeStrokeTextColor;
	
	/** */
	private Color inactiveParagraphTextColor;
	
	/** */
	private Color inactiveStrokeColor;
	
	/** */
	private Color disabledTextColor;
	
	/** */
	private Color disabledStrokeColor;
	
	/** */
	private Image disabledButton;
	
	/** */
	private float fontSize;
	
	/** */
	//TODO: make it real!
	private Image clicImage;
	
	/**
	 * @throws IOException  */
	private OverallGUILayoutFactory()
	{
	}
	
	/**
	 * @return the generalFocusedButton
	 */
	public Image getSelectedButton() {
		return selectedButton;
	}

	/**
	 * @return the generalUnfocusedButton
	 */
	public Image getUnselectedButton() {
		return unselectedButton;
	}

	/**
	 * @return the text
	 */
	public Font getParagraphFont() {
		return paragraphFont;
	}
	/**
	 * @param text the text to set
	 */
	public void setParagraphFont(Font font) {
		this.paragraphFont = font;
	}
	/**
	 * @return the clicImage
	 */
	public Image getClicImage() {
		return clicImage;
	}
	/**
	 * @param clicImage the clicImage to set
	 */
	public void setClicImage(Image clicImage) {
		this.clicImage = clicImage;
	}
	/**
	 * @param generalFocusedButton the generalFocusedButton to set
	 */
	public void setSelectedButton(Image selectedButton) {
		this.selectedButton = selectedButton;
	}
	/**
	 * @param generalUnfocusedButton the generalUnfocusedButton to set
	 */
	public void setUnselectedButton(Image unselectedButton) {
		this.unselectedButton = unselectedButton;
	}
	
	/**
	 * @throws IOException 
	 * @throws FontFormatException  */
	public void setUp(Map infoMap) throws FontFormatException, IOException
	{
		// Keys list for getting values from the map
		final String SELECTED_BUTTON = "mainbutton.active.path", 
				UNSELECTED_BUTTON = "mainbutton.inactive.path", 
				DISABLED_BUTTON = "mainbutton.disabled.path",
				MAIN_BUTTON_ACTIVE_TEXT_COLOR = "mainbutton.active.text.color",
				MAIN_BUTTON_ACTIVE_STROKE_COLOR = "mainbutton.active.stroke.color",
				MAIN_BUTTON_INACTIVE_TEXT_COLOR = "mainbutton.inactive.text.color",
				MAIN_BUTTON_INACTIVE_STROKE_COLOR = "mainbutton.inactive.stroke.color",
				MAIN_BUTTON_DISABLED_STROKE_COLOR = "mainbutton.disabled.stroke.color",
				MAIN_BUTTON_DISABLED_TEXT_COLOR = "mainbutton.disabled.text.color",
				HEADER_FONT = "fonth.path",
				PARAGRAPH_FONT = "fontp.path",
				ERROR_IMAGE = "error.img.path";
		
		// Load fonts
		setParagraphFont(Font.createFont(Font.TRUETYPE_FONT, new File((String)infoMap.get(PARAGRAPH_FONT))));
		setHeaderFont(Font.createFont(Font.TRUETYPE_FONT, new File((String)infoMap.get(HEADER_FONT))));
		
		// Load images for buttons
		setSelectedButton((new ImageIcon((String)infoMap.get(SELECTED_BUTTON))).getImage());
		setUnselectedButton((new ImageIcon((String)infoMap.get(UNSELECTED_BUTTON))).getImage());
		setDisabledButton((new ImageIcon((String)infoMap.get(DISABLED_BUTTON))).getImage());
		setErrorImage((new ImageIcon((String)infoMap.get(ERROR_IMAGE))).getImage());
		
		// Load colors for the text 'types'
		activeParagraphTextColor = Color.decode("#"+(String)infoMap.get(MAIN_BUTTON_ACTIVE_TEXT_COLOR));
		activeStrokeTextColor = Color.decode("#"+(String)infoMap.get(MAIN_BUTTON_ACTIVE_STROKE_COLOR));
		inactiveParagraphTextColor = Color.decode("#"+(String)infoMap.get(MAIN_BUTTON_INACTIVE_TEXT_COLOR));
		inactiveStrokeColor = Color.decode("#"+(String)infoMap.get(MAIN_BUTTON_INACTIVE_STROKE_COLOR));
		disabledTextColor = Color.decode("#"+(String)infoMap.get(MAIN_BUTTON_DISABLED_TEXT_COLOR));
		disabledStrokeColor = Color.decode("#"+(String)infoMap.get(MAIN_BUTTON_DISABLED_STROKE_COLOR));
	}
	/**
	 * @return the headerFont
	 */
	public Font getHeaderFont() 
	{
		return headerFont;
	}
	/**
	 * @param headerFont the headerFont to set
	 */
	public void setHeaderFont(Font headerFont) {
		this.headerFont = headerFont;
	}
	
	/** */
	public Color getParsedColor(final String color)
	{
		return new Color(Integer.parseInt(color,16));
	}
	/** */
	public Dimension getParsedDimension(final String width, final String height)
	{
		return new Dimension(Integer.parseInt(width), Integer.parseInt(height));
	}
	
	/** */
	public JButton createButton(float fontSize, final String text, int width, int height)
	{
		// Create images for icon
		ImageIcon inactive = new ImageIcon(createImageButton(fontSize, text, width, height, BUTTON_STATE_INACTIVE));
		ImageIcon active = new ImageIcon(createImageButton(fontSize, text, width, height, BUTTON_STATE_ACTIVE));
		ImageIcon disabled = new ImageIcon(createImageButton(fontSize, text, width, height, BUTTON_STATE_DISABLED));
		
		JButton button = new JButton(inactive);
		button.setRolloverIcon(active);
		button.setSelectedIcon(active);
		button.setDisabledIcon(disabled);
		button.setDisabledSelectedIcon(inactive);
		button.setBorderPainted(false);
		return button;
	}
	
	/** */
	public JButton createButtonUniState(float fontSize, final String text, int width, int height, int buttonState)
	{
		ImageIcon icon = new ImageIcon(createImageButton(fontSize, text, width, height, buttonState));
		JButton button = new JButton(icon);
		button.setBorderPainted(false);
		button.setRolloverIcon(icon);
		button.setSelectedIcon(icon);
		Dimension dimension = new Dimension(width,height);
		button.setPreferredSize(dimension);
		button.setMaximumSize(dimension);
		button.setMaximumSize(dimension);
		button.setSize(dimension);
		return button;
	}
	
	/** */
	public Image createImageButton(float fontSize, final String text, int width, int height, int buttonState)
	{
		Color outstroke = null, textColor = null;
		TextLayout textLayout = new TextLayout(text, paragraphFont.deriveFont(fontSize), new FontRenderContext(null, false, false));
		Shape textRectagleShape = textLayout.getOutline(null);
		
		Image buttonImage = null;
		
		switch (buttonState) {
		case BUTTON_STATE_ACTIVE:
			outstroke = activeStrokeTextColor;
			textColor = activeParagraphTextColor;
			buttonImage = selectedButton;
			break;
		case BUTTON_STATE_INACTIVE:
			outstroke = inactiveStrokeColor;
			textColor = inactiveParagraphTextColor;
			buttonImage = unselectedButton;
			break;
		case BUTTON_STATE_DISABLED:
			outstroke = disabledTextColor;
			textColor = disabledTextColor;
			buttonImage = disabledButton;
			break;
		default:
			return null;
		}
		
		BufferedImage bufferedImage = new BufferedImage(buttonImage.getWidth(null), buttonImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
		Graphics2D graphics= bufferedImage.createGraphics();
		Rectangle textRectangle = textRectagleShape.getBounds();

		this.setAntiAlias(graphics);
		
		int imageWidth = buttonImage.getWidth(null), imageHeight = buttonImage.getHeight(null), bImageWidth = bufferedImage.getWidth();
			
		graphics.drawImage(buttonImage, 0, 0, imageWidth, imageHeight, null);
		graphics.translate((bImageWidth-textRectangle.width)/2, (imageHeight+textRectangle.height)/2);
		graphics.setStroke(new BasicStroke(5.0f));
		graphics.setBackground(new Color(transparentColor));
		
		graphics.fill(textRectagleShape);
		graphics.setColor(outstroke);
		graphics.draw(textRectagleShape);

		graphics.setStroke(new BasicStroke(0.0f));
		graphics.setColor(textColor);
		graphics.setPaint(textColor);

		graphics.fill(textRectagleShape);
		graphics.draw(textRectagleShape);
		
		graphics.dispose();
		return Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(bufferedImage.getSource(), transparentFilter)).getScaledInstance(width, height, Image.SCALE_SMOOTH);
	}

	/** */
	public Image createImageButton(float fontSize, final String text, Color textColor, float stroke, Color outstroke, int width, int height, String buttonIcontPath, Font font)
	{
		TextLayout textLayout = new TextLayout(text, font.deriveFont(fontSize), new FontRenderContext(null, false, false));
		Shape textRectagleShape = textLayout.getOutline(null);
		
		Image buttonImage = new ImageIcon(buttonIcontPath).getImage();
		
		
		BufferedImage bufferedImage = new BufferedImage(buttonImage.getWidth(null), buttonImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
		Graphics2D graphics= bufferedImage.createGraphics();
		Rectangle textRectangle = textRectagleShape.getBounds();

		this.setAntiAlias(graphics);
		int imageWidth = buttonImage.getWidth(null), imageHeight = buttonImage.getHeight(null), bImageWidth = bufferedImage.getWidth();
			
		graphics.drawImage(buttonImage, 0, 0, imageWidth, imageHeight, null);
		graphics.translate((bImageWidth-textRectangle.width)/2, (imageHeight+textRectangle.height)/2);
		graphics.setStroke(new BasicStroke(stroke));
//		graphics.setBackground(ts);
		
		graphics.fill(textRectagleShape);
		graphics.setColor(outstroke);
		graphics.draw(textRectagleShape);

		graphics.setStroke(new BasicStroke(0.0f));
		graphics.setColor(textColor);
		graphics.setPaint(textColor);

		graphics.fill(textRectagleShape);
		graphics.draw(textRectagleShape);
		
		graphics.dispose();
		return bufferedImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
	}
	
	public Image createTextImage(String text, float fontSize, Font font, float strokeSize, Color textColor, Color strokeColor)
	{
		TextLayout textLayout = new TextLayout(text, font.deriveFont(fontSize), new FontRenderContext(null, false, false));
		Shape textRectagleShape = textLayout.getOutline(null);
		
		int width = (int)textLayout.getBounds().getWidth(), height = (int)textLayout.getBounds().getHeight();
		BufferedImage bufferedImage = new BufferedImage(width*2, height*2, BufferedImage.TYPE_INT_ARGB);
		Graphics2D graphics= bufferedImage.createGraphics();
		
		this.setAntiAlias(graphics);
		
		graphics.translate(width-(width/2), height+(height/2));
		graphics.setStroke(new BasicStroke(strokeSize));
		graphics.setBackground(new Color(transparentColor));
		
		graphics.fill(textRectagleShape);
		graphics.setColor(strokeColor);
		graphics.draw(textRectagleShape);

		graphics.setStroke(new BasicStroke(0.0f));
		graphics.setColor(textColor);
		graphics.setPaint(textColor);

		graphics.fill(textRectagleShape);
		graphics.draw(textRectagleShape);
		
		graphics.dispose();
		return Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(bufferedImage.getSource(), transparentFilter)).getScaledInstance(width, height, Image.SCALE_SMOOTH);
	}
	/**
	 * @return the activeParagraphTextColor
	 */
	public Color getActiveParagraphTextColor() {
		return activeParagraphTextColor;
	}

	/**
	 * @param activeParagraphTextColor the activeParagraphTextColor to set
	 */
	public void setActiveParagraphTextColor(Color activeParagraphTextColor) {
		this.activeParagraphTextColor = activeParagraphTextColor;
	}

	/**
	 * @return the activeStrokeTextColor
	 */
	public Color getActiveStrokeTextColor() {
		return activeStrokeTextColor;
	}

	/**
	 * @param activeStrokeTextColor the activeStrokeTextColor to set
	 */
	public void setActiveStrokeTextColor(Color activeStrokeTextColor) {
		this.activeStrokeTextColor = activeStrokeTextColor;
	}

	/**
	 * @return the inactiveParagraphTextColor
	 */
	public Color getInactiveParagraphTextColor() {
		return inactiveParagraphTextColor;
	}

	/**
	 * @param inactiveParagraphTextColor the inactiveParagraphTextColor to set
	 */
	public void setInactiveParagraphTextColor(Color inactiveParagraphTextColor) {
		this.inactiveParagraphTextColor = inactiveParagraphTextColor;
	}

	/**
	 * @return the inactiveStrokeColor
	 */
	public Color getInactiveStrokeColor() {
		return inactiveStrokeColor;
	}

	/**
	 * @param inactiveStrokeColor the inactiveStrokeColor to set
	 */
	public void setInactiveStrokeColor(Color inactiveStrokeColor) {
		this.inactiveStrokeColor = inactiveStrokeColor;
	}

	/**
	 * @return the fontSize
	 */
	public float getFontSize() {
		return fontSize;
	}

	/**
	 * @param fontSize the fontSize to set
	 */
	public void setFontSize(float fontSize) {
		this.fontSize = fontSize;
	}

	/**
	 * @return the disabledTextColor
	 */
	public Color getDisabledTextColor() {
		return disabledTextColor;
	}

	/**
	 * @param disabledTextColor the disabledTextColor to set
	 */
	public void setDisabledTextColor(Color disabledTextColor) {
		this.disabledTextColor = disabledTextColor;
	}

	/**
	 * @return the disabledStrokeColor
	 */
	public Color getDisabledStrokeColor() {
		return disabledStrokeColor;
	}

	/**
	 * @param disabledStrokeColor the disabledStrokeColor to set
	 */
	public void setDisabledStrokeColor(Color disabledStrokeColor) {
		this.disabledStrokeColor = disabledStrokeColor;
	}

	/**
	 * @return the disabledButton
	 */
	public Image getDisabledButton() {
		return disabledButton;
	}

	/**
	 * @param disabledButton the disabledButton to set
	 */
	public void setDisabledButton(Image disabledButton) {
		this.disabledButton = disabledButton;
	}
	
	private void setAntiAlias(Graphics2D graphics)
	{
		graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

		// for antialiasing text
		graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON );

		// to go for quality over speed
		graphics.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY );
	}

	/**
	 * @return the errorImage
	 */
	public Image getErrorImage() {
		return errorImage;
	}

	/**
	 * @param errorImage the errorImage to set
	 */
	public void setErrorImage(Image errorImage) {
		this.errorImage = errorImage;
	}
}
